package com.taint.callgraph;

import com.taint.agent.FlowTaintAgent;
import com.taint.logger.TraceEndpoint;
import com.taint.logger.TraceEntry;
import com.taint.logger.TraceLog;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Stack;

public class CallRecorder {


    static final Map<Long, CallGraph> GRAPHS = new HashMap<>();

    public static TraceEntry MethodBefore(TraceEndpoint traceEndpoint, String type, String method, String sig, Object[] args) {
        TraceItem traceItem = new TraceItem(type, method, sig);
        TraceEntry entry = TraceLog.NewTraceEntry(traceEndpoint, traceItem, args);

        RecodrerBefore(traceItem);
        return entry;
    }

    public static void RecodrerBefore(TraceItem traceItem) {

        //压栈
        FlowTaintAgent.stacks.get().push(traceItem);
        //添加函数
        FlowTaintAgent.calls.get().add(traceItem);

    }


    public static void MethodBefore(TraceItem traceItem) {
        long threadId = Thread.currentThread().getId();
        CallGraph graph = GRAPHS.get(threadId);
        if (graph == null) {
            graph = new CallGraph(threadId);
            GRAPHS.put(threadId, graph);
        }
        //graph.called(traceItem);
    }


    public static void MethodAfter(TraceEndpoint traceEndpoint, TraceEntry entry, Object returned) {
        StackTraceElement[] stackTraceElements = new Throwable().getStackTrace();
        entry.traceItem.setStacktrace(CallStack.PrintStack(stackTraceElements));
        entry.traceItem.setReturned(returned);
        TraceLog.Log(entry);
        RecodrerAfter(entry.traceItem);
        /*
        long threadId = Thread.currentThread().getId();
        CallGraph graph = GRAPHS.get(threadId);
        if (graph == null) {
            // not interesting
            return;
        }
        */
        //graph.exited(item);

    }

    private static void RecodrerAfter(TraceItem traceItem) {
        //出栈
        FlowTaintAgent.stacks.get().pop();
        //如果栈为空，那说明正好全部都出栈了
        if (FlowTaintAgent.stacks.get().empty()) {
            System.out.println("test " + FlowTaintAgent.calls.get() + " size:" + FlowTaintAgent.calls.get().size());
            //记录下来
            FlowTaintAgent.stacks.set(new Stack<TraceItem>());
            FlowTaintAgent.calls.set(new LinkedList<TraceItem>());
        }


    }


}
